import binascii
import copy
import csv
import logging
import os
import queue
import re
import sys
import time
from ast import Pass
from ctypes import *
from distutils.log import error
from operator import index
from threading import Thread
from tracemalloc import start

import bincopy
import numpy as np
import pandas as pd
import pytest
from regex import R

import TSMasterAPI

class DB_Variable:
    DT_STR_Network_Name = 0                                       # 获取网络名称
    DT_STR_DBC_FileName = 1                                       # 获取dbc文件名
    DT_INT_Protocol_Type = 2                                      # 获取协议类型，0=CAN; 1=FD; 2=J1939
    DT_INT_3 = 3                                                  # unused
    DT_INT_4 = 4                                                  # unused
    DT_INT_5 = 5                                                  # unused
    DT_INT_6 = 6                                                  # unused
    DT_INT_7 = 7                                                  # unused
    DT_INT_8 = 8                                                  # unused
    DT_INT_9 = 9                                                  # unused
    DT_INT_Signal_List_Count = 10                                 # 获取信号表数量 = db.sgns.count
    DT_INT_CAN_Message_List_Count = 11                            # 获取CAN报文表数量 = db.msgs.count
    DT_INT_CANFD_Message_List_Count = 12                          # 获取CAN FD报文表数量 = db.msgsFD.count
    DT_INT_CANJ1939_Message_List_Count = 13                       # 获取CAN J1939报文表数量 = db.msgsJ1939.count
    DT_INT_Node_List_Count = 14                                   # 获取节点表数量 = db.nodes.count
    DT_INT_EnvVar_List_Count = 15                                 # 获取环境变量表数量 = db.envs.count
    DT_INT_ValTab_List_Count = 16                                 # 获取取值表数量 = db.valtabs.count
    DT_INT_17 = 17                                                # unused
    DT_INT_18 = 18                                                # unused
    DT_INT_19 = 19                                                # unused
    DT_INT_Signal_List_Message_ID = 20                            # 获取信号表中第idx信号所在的报文标识符 db.sgns[idx].message_id
    DT_INT_Signal_List_Value_Type = 21                            # 获取信号表中第idx信号值类型 0-无符号整型 1-有符号整型 2-32位浮点 3-64位浮点
    DT_INT_Signal_List_Is_Motorola = 22                           # 获取信号表中第idx信号是否是Motorola格式，0-Intel格式、1-Motorola格式
    DT_INT_Signal_List_ValTab_Index = 23                          # 获取信号表中第idx信号所带的取值表在取值表列表中的索引
    DT_INT_Signal_List_Mux_Type = 24                              # 获取信号表中第idx信号Mux类型，0-普通信号, 1-multiplexor, 2-multiplexed信号
    DT_INT_Signal_List_Mux_Value = 25                             # 获取信号表中第idx信号作为multiplexor的值
    DT_INT_Signal_List_Layout_Start = 26                          # 获取信号表中第idx信号在报文中的起始位
    DT_INT_Signal_List_Length = 27                                # 获取信号表中第idx信号的信号长度
    DT_DBL_Signal_List_Factor = 28                                # 获取信号表中第idx信号放大因子
    DT_DBL_Signal_List_Offset = 29                                # 获取信号表中第idx信号偏移量
    DT_DBL_Signal_List_InitValue = 30                             # 获取信号表中第idx信号初始值
    DT_DBL_Signal_List_Min = 31                                   # 获取信号表中第idx信号最小值
    DT_DBL_Signal_List_Max = 32                                   # 获取信号表中第idx信号最大值
    DT_STR_Signal_List_Name = 33                                  # 获取信号表中第idx信号名称
    DT_STR_Signal_List_Unit = 34                                  # 获取信号表中第idx信号单位
    DT_STR_Signal_List_Comment = 35                               # 获取信号表中第idx信号注释
    DT_INT_Signal_List_Message_Index = 36                         # 获取信号表中第idx信号所在的报文在报文表中的索引 db.msgs[db.sgns[idx].message_idx]
    DT_INT_Signal_List_Message_Type = 37                          # 获取信号表中第idx信号所在的报文的类型，0=CAN, 1=CANFD, 2=J1939
    DT_STR_Signal_List_Struct = 38                                # 获取信号表中第idx信号全部属性，逗号分隔 db.sgns[idx]
    DT_INT_39 = 39                                                # unused
    DT_INT_CAN_Message_List_Type = 40                             # 获取CAN报文表中第idx报文类型，cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_CAN_Message_List_DLC = 41                              # 获取CAN报文表中第idx报文数据长度
    DT_INT_CAN_Message_List_ID = 42                               # 获取CAN报文表中第idx报文标识符
    DT_INT_CAN_Message_List_CycleTime = 43                        # 获取CAN报文表中第idx报文周期
    DT_STR_CAN_Message_List_Name = 44                             # 获取CAN报文表中第idx报文名称
    DT_STR_CAN_Message_List_Comment = 45                          # 获取CAN报文表中第idx报文注释
    DT_INT_CAN_Message_List_TX_Node_Index = 46                    # 获取CAN报文表中第idx报文对应的发送节点的索引
    DT_INT_CAN_Message_List_Owned_Signal_List_Count = 47          # 获取CAN报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_CAN_Message_List_Owned_Signal_List_Signal_Index = 48   # 获取CAN报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_STR_CAN_Message_List_Struct = 49                           # 获取CAN报文表中第idx报文全部属性，逗号分隔 db.msgs[idx]
    DT_INT_50 = 50                                                # unused
    DT_INT_51 = 51                                                # unused
    DT_INT_52 = 52                                                # unused
    DT_INT_53 = 53                                                # unused
    DT_INT_54 = 54                                                # unused
    DT_INT_55 = 55                                                # unused
    DT_INT_56 = 56                                                # unused
    DT_INT_57 = 57                                                # unused
    DT_INT_58 = 58                                                # unused
    DT_INT_59 = 59                                                # unused
    DT_INT_CANFD_Message_List_Type = 60                           # 获取CANFD报文表中第idx报文类型，cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_CANFD_Message_List_DLC = 61                            # 获取CANFD报文表中第idx报文数据长度
    DT_INT_CANFD_Message_List_ID = 62                             # 获取CANFD报文表中第idx报文标识符
    DT_INT_CANFD_Message_List_CycleTime = 63                      # 获取CANFD报文表中第idx报文周期
    DT_STR_CANFD_Message_List_Name = 64                           # 获取CANFD报文表中第idx报文名称
    DT_STR_CANFD_Message_List_Comment = 65                        # 获取CANFD报文表中第idx报文注释
    DT_INT_CANFD_Message_List_TX_Node_Index = 66                  # 获取CANFD报文表中第idx报文对应的发送节点的索引
    DT_INT_CANFD_Message_List_Owned_Signal_List_Count = 67        # 获取CANFD报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_CANFD_Message_List_Owned_Signal_List_Signal_Index = 68 # 获取CANFD报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_INT_CANFD_Message_List_BRS = 69                            # 获取CANFD报文表中第idx报文BRS，0-No BRS、1-BRS
    DT_STR_CANFD_Message_List_Struct = 70                         # 获取CANFD报文表中第idx报文全部属性，逗号分隔 db.msgs[idx]
    DT_INT_71 = 71                                                # unused
    DT_INT_72 = 72                                                # unused
    DT_INT_73 = 73                                                # unused
    DT_INT_74 = 74                                                # unused
    DT_INT_75 = 75                                                # unused
    DT_INT_76 = 76                                                # unused
    DT_INT_77 = 77                                                # unused
    DT_INT_78 = 78                                                # unused
    DT_INT_79 = 79                                                # unused
    DT_INT_J1939_Message_List_Type = 80                           # 获取J1939报文表中第idx报文类型，cftStdCAN = 0, cftExtCAN = 1, cftJ1939 = 2, cftStdCANFD = 3, cftExtCANFD = 4
    DT_INT_J1939_Message_List_DLC = 81                            # 获取J1939报文表中第idx报文数据长度
    DT_INT_J1939_Message_List_ID = 82                             # 获取J1939报文表中第idx报文标识符
    DT_INT_J1939_Message_List_CycleTime = 83                      # 获取J1939报文表中第idx报文周期
    DT_STR_J1939_Message_List_Name = 84                           # 获取J1939报文表中第idx报文名称
    DT_STR_J1939_Message_List_Comment = 85                        # 获取J1939报文表中第idx报文注释
    DT_INT_J1939_Message_List_TX_Node_Index = 86                  # 获取J1939报文表中第idx报文对应的发送节点的索引
    DT_INT_J1939_Message_List_Owned_Signal_List_Count = 87        # 获取J1939报文表中第idx报文拥有的信号数量 db.msgs[idx].sgns.count
    DT_INT_J1939_Message_List_Owned_Signal_List_Signal_Index = 88 # 获取J1939报文表中第idx报文中第subidx信号在信号表中的索引 db.sgns[db.sgns.indexof(db.msgs[idx].sgns[subidx])]
    DT_STR_J1939_Message_List_Struct = 89                         # 获取CAN报文表中第idx报文全部属性，逗号分隔 db.msgs[idx]
    DT_INT_90 = 90                                                # unused
    DT_INT_91 = 91                                                # unused
    DT_INT_92 = 92                                                # unused
    DT_INT_93 = 93                                                # unused
    DT_INT_94 = 94                                                # unused
    DT_INT_95 = 95                                                # unused
    DT_INT_96 = 96                                                # unused
    DT_INT_97 = 97                                                # unused
    DT_INT_98 = 98                                                # unused
    DT_INT_99 = 99                                                # unused
    DT_INT_Node_List_Address = 100                                # 获取节点表中第idx节点地址，默认为0
    DT_STR_Node_List_Name = 101                                   # 获取节点表中第idx节点名称
    DT_STR_Node_List_Comment = 102                                # 获取节点表中第idx节点注释
    DT_INT_Node_List_TX_CAN_Message_List_Count = 103              # 获取节点表中第idx节点所发送的CAN报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_CAN_Message_List_Message_Index = 104      # 获取节点表中第idx节点所发送的subidx报文在CAN报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_CAN_Message_List_Count = 105              # 获取节点表中第idx节点所接收的CAN报文数量
    DT_INT_Node_List_RX_CAN_Message_List_Message_Index = 106      # 获取节点表中第idx节点所接收的subidx报文在CAN报文表中的索引
    DT_INT_Node_List_TX_FD_Message_List_Count = 107               # 获取节点表中第idx节点所发送的FD报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_FD_Message_List_Message_Index = 108       # 获取节点表中第idx节点所发送的subidx报文在FD报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_FD_Message_List_Count = 109               # 获取节点表中第idx节点所接收的FD报文数量
    DT_INT_Node_List_RX_FD_Message_List_Message_Index = 110       # 获取节点表中第idx节点所接收的subidx报文在FD报文表中的索引
    DT_INT_Node_List_TX_J1939_Message_List_Count = 111            # 获取节点表中第idx节点所发送的J1939报文数量 db.nodes[idx].txmsgs.count
    DT_INT_Node_List_TX_J1939_Message_List_Message_Index = 112    # 获取节点表中第idx节点所发送的subidx报文在J1939报文表中的索引 db.msgs[db.msgs.indexof(db.nodes[idx].txmsgs[subidx])]
    DT_INT_Node_List_RX_J1939_Message_List_Count = 113            # 获取节点表中第idx节点所接收的J1939报文数量
    DT_INT_Node_List_RX_J1939_Message_List_Message_Index = 114    # 获取节点表中第idx节点所接收的subidx报文在J1939报文表中的索引
    DT_INT_Node_List_TX_Signal_List_Count = 115                   # 获取节点表中第idx节点所发送的信号数量
    DT_INT_Node_List_TX_Signal_List_Signal_Index = 116            # 获取节点表中第idx节点所发送的subidx信号在信号表中的索引
    DT_INT_Node_List_RX_Signal_List_Count = 117                   # 获取节点表中第idx节点所接收的信号数量
    DT_INT_Node_List_RX_Signal_List_Signal_Index = 118            # 获取节点表中第idx节点所接收的subidx信号在信号表中的索引
    DT_STR_Node_List_Struct = 119                                 # 获取节点表中第idx节点全部属性，逗号分隔 db.nodes[idx]
    DT_INT_120 = 120                                              # unused
    DT_INT_121 = 121                                              # unused
    DT_INT_122 = 122                                              # unused
    DT_INT_123 = 123                                              # unused
    DT_INT_124 = 124                                              # unused
    DT_INT_125 = 125                                              # unused
    DT_INT_126 = 126                                              # unused
    DT_INT_127 = 127                                              # unused
    DT_INT_128 = 128                                              # unused
    DT_INT_129 = 129                                              # unused
    DT_INT_EnvVar_List_Value_Type = 130                           # 获取环境变量表中第idx环境变量值类型，0-整型、1-浮点、2-字符串、3-数据
    DT_DBL_EnvVar_List_MIN = 131                                  # 获取环境变量表中第idx环境变量最小值
    DT_DBL_EnvVar_List_MAX = 132                                  # 获取环境变量表中第idx环境变量最大值
    DT_DBL_EnvVar_List_Init_Value = 133                           # 获取环境变量表中第idx环境变量初始值
    DT_STR_EnvVar_List_Name = 134                                 # 获取环境变量表中第idx环境变量名称
    DT_STR_EnvVar_List_Unit = 135                                 # 获取环境变量表中第idx环境变量单位
    DT_STR_EnvVar_List_Comment = 136                              # 获取环境变量表中第idx环境变量注释
    DT_STR_EnvVar_List_Struct = 137                               # 获取环境变量表中第idx环境变量全部属性，逗号分隔 db.EnvVars[idx]
    DT_INT_138 = 138                                              # unused
    DT_INT_139 = 139                                              # unused
    DT_INT_ValTab_List_Item_List_Count = 140                      # 获取取值表中第idx取值表所包含的值数量
    DT_INT_ValTab_List_Item_List_Name = 141                       # 获取取值表中第idx取值表名称
    DT_DBL_ValTab_List_Item_List_Value = 142                      # 获取取值表中第idx取值表中第subidx的值
    DT_STR_ValTab_List_Struct = 143                               # 获取取值表中第idx取值表全部属性，逗号分隔 db.ValTabs[idx]

# q=queue.Queue(10000)
# obj_HIL_q=queue.Queue(10000)

def On_CAN_EVENT(OBJ, ACAN):
    if (ACAN.contents.FIdentifier == 0x777 and ACAN.contents.FIdxChn == 0):
        logging.info("CAN回调接收成功")
        for i in ACAN.contents.FData:
            print('%#x' % i, end=' ')
        logging.info('')
    CAN_data = pd.Series({'AIdxChn':ACAN.contents.FIdxChn,
                            'AIsTx':0,
                            'AIsRemote':0,
                            'AIsExtended':ACAN.contents.FProperties,
                            'AIsError':0,
                            'ADLC':ACAN.contents.FDLC,
                            'AIdentifier':ACAN.contents.FIdentifier,
                            'ATimeUs':ACAN.contents.FTimeUs/1000000.0,
                            'ADatas':ACAN.contents.FData}) 
OnCANevent = TSMasterAPI.OnTx_RxFUNC_CAN(On_CAN_EVENT)

def On_CANFD_EVENT(OBJ, ACAN):
    if (ACAN.contents.FIdentifier == 0x666 and ACAN.contents.FIdxChn == 0):
        # print("CANFD 0x666 回调接收成功")
        # for i in ACAN.contents.FData:
        #     print('%#x' % i, end=' ')
        # print('')
        pass
    if (ACAN.contents.FIdentifier == 0x777 and ACAN.contents.FIdxChn == 0):
        # print("CAN 0x777 回调接收成功")
        # for i in ACAN.contents.FData:
        #     print('%#x' % i, end=' ')
        # print('')
        pass
    # CAN_data = pd.Series({'AIdxChn':ACAN.contents.FIdxChn,
    #                         'AIsTx':0,
    #                         'AIsExtended':ACAN.contents.FProperties,
    #                         'AIsError':0,
    #                         'AIsEDL':0,
    #                         'AIsBRS':ACAN.contents.FFDProperties,
    #                         'AIsESI':0,
    #                         'ADLC':ACAN.contents.FDLC,
    #                         'AIdentifier':ACAN.contents.FIdentifier,
    #                         'ATimeUs':ACAN.contents.FTimeUs/1000000.0,
    #                         'ADatas':ACAN.contents.FData})
    # try:
    #     q.put(CAN_data)
    # except queue.Full:
    #     q.queue.clear()
    #     print('queue.Full') 
    pass   
OnCANFDevent = TSMasterAPI.OnTx_RxFUNC_CANFD(On_CANFD_EVENT)

class TSCAN(object):
    def __init__(self,drive_type = 'USE_TS_VIRTUAL_DEVICE',
                configure_baudrate = {'CAN_Type':'CANFD','ArbRate':500,'DataRate':2000,'TermResistor':True},
                ChannelIndex = TSMasterAPI.CHANNEL_INDEX.CHN1,
                APP_NAME = "Auto_TS_Test",
                totle_channel_count = 1
                ):
        error_code = 0
        self.drive_type = drive_type
        self.configure_baudrate = configure_baudrate
        self.ChannelIndex = ChannelIndex
        self.APP_NAME = APP_NAME.encode("utf-8")
        self.EnableNode= []
        self.FrameData = [0,0,0,0,0,0,0,0]
        # self.bufferszie = copy.copy(c_uint32(100000))
        self.bufferszie = copy.deepcopy(c_uint32(10000))

        # init TS CAN variable
        self.cFD = TSMasterAPI.TLIBCANFD()
        self.c = TSMasterAPI.TLIBCAN()

        self.cFD_buffer=[]
        for i in range(10000):
            cfd = TSMasterAPI.TLIBCANFD()
            self.cFD_buffer.append(cfd)
        self.c_buffer=[]
        for i in range(10000):
            c = TSMasterAPI.TLIBCAN()
            self.c_buffer.append(c)

        self.idDBC = c_uint32(0)  # 加载dbc句柄
        self.obj = c_int32(0)
        self.read_frame_ALl_data = pd.DataFrame()

        # 初始化函数（是否使能fifo,是否激活极速模式）
        if 0 == TSMasterAPI.dll.initialize_lib_tsmaster(self.APP_NAME):
            logging.info('initialize_lib_tsmaster success ')
        else:
            logging.warning('initialize_lib_tsmaster error ' )
        # if 0 == TSMasterAPI.dll.tsapp_set_turbo_mode(True):
        #     print('set_turbo_mode True success ')
        # else:
        #     print('set_turbo_mode True error')

        # set CAN channel count to 2
        if 0 == TSMasterAPI.tsapp_set_can_channel_count(totle_channel_count):
            logging.info('set_can_channel_coun to  {0}'.format(totle_channel_count))
        else:
            logging.warning('set_can_channel_coun error: {0} '.format(totle_channel_count) )
        
        # map application channel 1 to hw index 0, channel 0 of Vector virtual channel
        m = TSMasterAPI.TLIBTSMapping()
        m.FAppName = self.APP_NAME
        m.FAppChannelIndex = self.ChannelIndex.value
        m.FAppChannelType = TSMasterAPI.TLIBApplicationChannelType.APP_CAN.value
        m.FHWIndex = 0
        m.FHWChannelIndex = self.ChannelIndex.value
        
        if self.drive_type == 'USE_XL_VIRTUAL_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.XL_USB_DEVICE.value
            m.FHWDeviceSubType = 1
        elif self.drive_type == 'USE_XL_VN1630_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.XL_USB_DEVICE.value
            m.FHWDeviceSubType = 57
        elif self.drive_type == 'USE_XL_VN1640_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = 59
        elif self.drive_type == 'USE_TS_VIRTUAL_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_TCP_DEVICE.value
            m.FHWDeviceSubType = -1
        elif self.drive_type == 'USE_TS_TC1014_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1014.value
        elif self.drive_type == 'USE_TS_TC1016_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1016.value
        elif self.drive_type == 'USE_TS_TC1011_DEVICE':
            m.FHWDeviceType = TSMasterAPI.TLIBBusToolDeviceType.TS_USB_DEVICE.value
            m.FHWDeviceSubType = TSMasterAPI.TLIB_TS_Device_Sub_Type.TC1011.value
        
        m.FHWDeviceName = self.drive_type.encode("UTF8")
        r = TSMasterAPI.tsapp_set_mapping(m)
        if 0 == r:
            logging.info("TSCAN Driver started, and the CAN driver is {0}".format(self.drive_type))
        else:
            logging.warning("TSCAN Driver map error, and the current CAN driver is {0}, error code is:{1}"
                            .format(self.drive_type,TSMasterAPI.tsapp_get_error_description(r)))

        # m.FAppChannelIndex = CH2  # CH2
        # m.FHWDeviceType = TS_TCP_DEVICE
        # m.FHWDeviceSubType = -1
        # m.FHWIndex = 0
        # m.FHWChannelIndex = CH2
        # set_mapping(m)

        # configure CAN channel baudrates before connection: Arb = 500K, Data = 2M
        if self.configure_baudrate['CAN_Type'] == 'CAN':
            TSMasterAPI. tsapp_configure_baudrate_can(self.ChannelIndex.value, 
                                                        self.configure_baudrate['ArbRate'], 
                                                        False, 
                                                        self.configure_baudrate['TermResistor'])
            logging.info('The currentCAN_Type is {0},ArbRate is {1}, TermResistor is {2}'
                 .format(self.configure_baudrate['CAN_Type'],self.configure_baudrate['ArbRate'],self.configure_baudrate['TermResistor']))
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            TSMasterAPI.tsapp_configure_baudrate_canfd(self.ChannelIndex.value, 
                                                        self.configure_baudrate['ArbRate'], self.configure_baudrate['DataRate'],
                                                        TSMasterAPI.TLIBCANFDControllerType.lfdtISOCAN.value, 
                                                        TSMasterAPI.TLIBCANFDControllerMode.lfdmNormal.value, 
                                                        self.configure_baudrate['TermResistor'])
            logging.info('The currentCAN_Type is {0},ArbRate is {1}, DataRate is {2},TermResistor is {3}'
                 .format(self.configure_baudrate['CAN_Type'],self.configure_baudrate['ArbRate'],self.configure_baudrate['DataRate'],
                            self.configure_baudrate['TermResistor']))        

        logging.info('Init Done')

    def load_dbc(self,DBC_File_Path,ASupportedChannelsBased = b"0"):
        TSMasterAPI.tsdb_unload_can_dbs()   # 解绑所有dbc
        self.dbchandle = c_int32(0)
        # if 0 == TSMasterAPI.tsdb_load_can_db(DBC_File_Path, "0", self.idDBC):         ##   Load DBC, Note: 加载dbc必须在app connect 之前
        if 0 == TSMasterAPI.tsdb_load_can_db(DBC_File_Path.encode('utf-8'), ASupportedChannelsBased, self.dbchandle):    
            logging.info('CAN/CAN-FD database loaded success! And load dbc file at {0} ASupportedChannelsBased'.format(ASupportedChannelsBased)) 
        else:
            logging.warning('load dbc error !!!, You dbc path is : {0}'.format(DBC_File_Path))
        pass

    def RBS_Config(self,NetName,EnableNode):
        self.EnableNode = EnableNode
        (rivUseDB, rivUseLast, rivUse0) = (c_int(0), c_int(1), c_int(2)) 
        if 0 == TSMasterAPI.tscom_can_rbs_configure(False, True, True, rivUseDB):   #   configure can rbs
            logging.info('can RBS_Config success')
        else:
            logging.warning('RBS_Config error')

        #   activate everything in rbs
        # TSMasterAPI.dll.tscom_can_rbs_activate_all_networks(True, True)
        r = TSMasterAPI.dll.tscom_can_rbs_activate_network_by_name(self.ChannelIndex.value,True,NetName.encode("utf8"),False)
        if  0 == r:
            pass
        else:
            logging.warning('NetName add to rbs error: {0}---{1}'.format(NetName,TSMasterAPI.tsapp_get_error_description(r)))
        # #   activate specification in rbs
        for node in self.EnableNode:
            r = TSMasterAPI.dll.tscom_can_rbs_activate_node_by_name(self.ChannelIndex.value,True, NetName.encode("utf8"), node.encode("utf8"), True)
            if 0 == r:
                logging.info('Enable rbs node : {0}'.format(node))
            else:
                logging.warning('node add to rbs error: {0}---{1}'.format(node,TSMasterAPI.tsapp_get_error_description(r)))
        r = TSMasterAPI.dll.tscom_can_rbs_start() #   start rbs
        if  0 == r: 
            logging.info("CAN RBS is started...")
        else:
            logging.warning("CAN RBS is started error:{0}".format(TSMasterAPI.tsapp_get_error_description(r)))

    def Enable_rbs_message(self,NetName,node,Message,Enalbe= True):
        r  = TSMasterAPI.dll.tscom_can_rbs_activate_message_by_name(self.ChannelIndex.value,Enalbe, NetName.encode("utf8"), node.encode("utf8"),Message.encode("utf8"), True)
        if 0 == r:
            logging.info('Enable rbs node :{0}---{1}'.format(Message,Enalbe))
        else:
            logging.warning('node add to rbs error: {0}---{1}'.format(Message,TSMasterAPI.tsapp_get_error_description(r)))
        pass

    def register_event_can_T_R(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_event_can(obj, eventdef): #   register can rx-tx event
            logging.info("CAN TX&RX callback successful")
        else:
            logging.warning("CAN TX&RX callback add error")
        return obj

    def register_event_can_T_pre(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_pretx_event_can(obj, eventdef): #   register can tx pre event
            logging.info("CAN TX Pre callback successful")
        else:
            logging.warning("CAN TX Pre callback add error")
        return obj

    def register_event_canfd_T_R(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_event_canfd(obj, eventdef): #   register canFD rx-tx event
            logging.info("CANFD TX&RX callback add successful")
        else:
            logging.warning("CANFD TX&RX callback add error")     
        return obj

    def register_event_canfd_T_pre(self,eventdef):
        obj = c_int32(0)
        if 0 == TSMasterAPI.tsapp_register_pretx_event_canfd(obj, eventdef): #   register canFD tx pre event
            logging.info("CANFD TX Pre callback add successful")
        else:
            logging.warning("CANFD TX Pre callback add error")     
        return obj
    
    def connect_application(self):
        # connect application
        r = TSMasterAPI.tsapp_connect()
        if  0==r:
            logging.info("TSMasterCDemo application connected, communication starts here...") 
        else:
            logging.warning("TSMasterCDemo application connected error :{0} ".format(TSMasterAPI.tsapp_get_error_description(r)))

        TSMasterAPI.tsfifo_enable_receive_fifo()    # 硬件开启成功后，开启fifo接收

        # 是否使能总线数据统计
        r = TSMasterAPI.dll.tsapp_enable_bus_statistics(True)
        if  0==r:
            logging.info("enable_bus_statistics...") 
        else:
            logging.warning("enable_bus_statistics error :{0}".format(TSMasterAPI.tsapp_get_error_description(r)))
        
    def dis_connect_application(self):
        #   [17] unregister pre-tx event
        # unregister_pretx_events_canfd(idpretx)
        # print("Unregister pretx event succeed")

        #   stop rbs
        if  0 == TSMasterAPI.dll.tscom_can_rbs_stop():
           logging.info("CAN RBS stopped")

        if 0 == TSMasterAPI.tsdb_unload_can_dbs():
            logging.info("unload_can_dbs")
        
        if 0 == TSMasterAPI.tsapp_disconnect():
            logging.info("TSMasterCDemo application disconnected")

        # TSMasterAPI.tsapp_del_application(APP_NAME)

        if 0 ==TSMasterAPI.finalize_lib_tsmaster():
            logging.info("TSMaster dll finalized")
    
    def send_Frame(self,ID,FrameData,CAN_Type = 'CAN'):
        self.FrameData = FrameData
        if CAN_Type == 'CANFD':
            self.cFD.FIdxChn = self.ChannelIndex.value.value
            self.cFD.FIdentifier = ID
            self.cFD.FProperties = 1       # 定义canfd数据类型  1:FD标准帧 5:FD扩展帧
            self.cFD.FFDProperties = 0x1   # 0:普通can数据帧 1：canfd数据帧
            self.cFD.FDLC = 15
            if len(self.FrameData) < 64:
                self.FrameData = self.FrameData +( [0] * (64 - len(FrameData)) )
            for i in range(len(self.FrameData)):
                self.cFD.FData[i] = self.FrameData[i]
            # TSMasterAPI.tsapp_transmit_canfd_async(self.cFD)    
            TSMasterAPI.dll.tsapp_transmit_canfd_async(byref(self.cFD)) # transmit this CANFD frame asynchrnously
            pass
        else:
            self.c.FIdxChn = self.ChannelIndex.value
            self.c.FIdentifier = ID
            self.c.FProperties = 1
            self.c.FDLC = 8
            for i in range(len(self.FrameData)):
                self.c.FData[i] = self.FrameData[i]
            # TSMasterAPI.tsapp_transmit_can_async(self.c)    
            TSMasterAPI.dll.tsapp_transmit_can_async(byref(self.c)) # transmit this classical CAN frame asynchrnously

    def TS_delay(self,delaytime):
        time.sleep(delaytime/1000)
    
    def set_read_buffersize(self,size=4096):
        self.bufferszie = copy.copy(c_uint32(size))

    def read_frame(self):
        # bufferszie = self.bufferszie
        bufferszie = copy.copy(c_uint32(4096))
        self.read_frame_ALl_data = self.read_frame_ALl_data.drop(index=self.read_frame_ALl_data.index)
        CAN_data = None
        # if q.qsize()>0:
        #     for i in range(q.qsize()):
        #         self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,q.get().to_frame().T],ignore_index=True)

        if self.configure_baudrate['CAN_Type'] == 'CAN':
            data = POINTER(TSMasterAPI.TLIBCAN * len(self.c_buffer))((TSMasterAPI.TLIBCAN * len(self.c_buffer))(*self.c_buffer))
            if 0 == TSMasterAPI.dll.tsfifo_receive_can_msgs(data, byref(bufferszie), self.ChannelIndex.value, TSMasterAPI.READ_TX_RX_DEF.ONLY_RX_MESSAGES):
                for i in range(bufferszie.value):
                    self.c_buffer[i] = data.contents[i]
                    CAN_data = pd.Series({'AIdxChn':data.contents[i].FIdxChn,
                                            'AIsTx':(data.contents[i].FProperties)&0x01,
                                            'AIsRemote':(data.contents[i].FProperties)&0x02,
                                            'AIsExtended':(data.contents[i].FProperties)&0x04,
                                            'AIsError':(data.contents[i].FProperties)&0x80,
                                            'ADLC':data.contents[i].FDLC,
                                            'AIdentifier':data.contents[i].FIdentifier,
                                            'ATimeUs':data.contents[i].FTimeUs/1000000.0,
                                            'ADatas':data.contents[i].FData
                                            })
                    self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,CAN_data.to_frame().T],ignore_index=True)
            else:
                logging.warning('read CAN error')                
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            data = POINTER(TSMasterAPI.TLIBCANFD * len(self.cFD_buffer))((TSMasterAPI.TLIBCANFD * len(self.cFD_buffer))(*self.cFD_buffer))
            if 0 == TSMasterAPI.dll.tsfifo_receive_canfd_msgs(data, byref(bufferszie), self.ChannelIndex.value, TSMasterAPI.READ_TX_RX_DEF.ONLY_RX_MESSAGES):
                for i in range(bufferszie.value):
                    self.cFD_buffer[i] = data.contents[i]
                    CAN_data = pd.Series({'AIdxChn':data.contents[i].FIdxChn,
                                            'AIsTx':(data.contents[i].FProperties)&0x01,
                                            'AIsRemote':(data.contents[i].FProperties)&0x02,
                                            'AIsExtended':(data.contents[i].FProperties)&0x04,
                                            'AIsError':(data.contents[i].FProperties)&0x80,
                                            'ADLC':data.contents[i].FDLC,
                                            'AIdentifier':data.contents[i].FIdentifier,
                                            'ATimeUs':data.contents[i].FTimeUs/1000000.0,
                                            'ADatas':data.contents[i].FData
                                            })
                    # FProperties:Byte  //default 0 , masked status:
                    # [7] 0-normal frame 1-normal frame 
                    # [6] 0-not logged  1-already  logged
                    # [5-3]  tbd
                    # [2] 0-std frame  1-Extended frame
                    # [1] 0-data frame  1-remote frame
                    # [0] fir : 0-RX 1-TX
                       
                    # 'AIsEDL':0,
                    # 'AIsBRS':ACAN.contents.FFDProperties,
                    # 'AIsESI':0,
                                        
                    self.read_frame_ALl_data = pd.concat([self.read_frame_ALl_data,CAN_data.to_frame().T],ignore_index=True)
            else:
                logging.warning('read CANFD error')
        logging.info('in read step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
        print('in read step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
        return self.read_frame_ALl_data,bufferszie.value

    def fush_q_buff(self):
        if self.configure_baudrate['CAN_Type'] == 'CAN':
            if 0 ==TSMasterAPI.tsfifo_clear_can_receive_buffers(self.ChannelIndex.value):
                pass
            else:
                logging.warning('clear CAN buffer error')
        elif self.configure_baudrate['CAN_Type'] == 'CANFD':
            if 0 == TSMasterAPI.tsfifo_clear_canfd_receive_buffers(self.ChannelIndex.value):
                pass 
            else:
                logging.warning('clear CANFD buffer error')

        # # print('qsize {0} will be clear'.format(q.qsize()))
        # q.queue.clear()
        # print('In fush step : Read fifo size {0} '.format(self.read_frame_ALl_data.shape[0]))
        self.read_frame_ALl_data = self.read_frame_ALl_data.drop(index=self.read_frame_ALl_data.index)

    def send_CANFrame_Cycle(self,ID,FrameData,cycletime,cycle_CAN_Type='CAN'):
        self.FrameData = FrameData
        cycle_ref = None
        if cycle_CAN_Type == 'CANFD':
            cycle_ref = TSMasterAPI.TLIBCANFD()
            # self.c = TSMasterAPI.TLIBCAN()
            cycle_ref.FIdxChn = self.ChannelIndex.value.value
            cycle_ref.FIdentifier = c_int32(ID)
            cycle_ref.FProperties = c_uint8(1)       # 定义canfd数据类型  1:FD标准帧 5:FD扩展帧
            cycle_ref.FFDProperties = 0x1   # 0:普通can数据帧 1：canfd数据帧
            cycle_ref.FDLC = 15
            if len(self.FrameData) < 64:
                self.FrameData = self.FrameData +( [0] * (64 - len(FrameData)) )
            for i in range(len(self.FrameData)):
                cycle_ref.FData[i] = self.FrameData[i]
            r = TSMasterAPI.tsapp_add_cyclic_msg_canfd(cycle_ref, cycletime) # send periodically
            if 0 == r:
                logging.info('tsapp_add_cyclic_msg_canfd:----'.format(hex(ID)))
            else:
                logging.warning('tsapp_add_cyclic_msg_canfd error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        elif cycle_CAN_Type == 'CAN':
            cycle_ref = TSMasterAPI.TLIBCAN()
            cycle_ref.FIdxChn = c_uint8(self.ChannelIndex.value.value)
            cycle_ref.FIdentifier = c_int32(ID)
            cycle_ref.FProperties = c_uint8(1)
            cycle_ref.FDLC = c_uint8(8)
            for i in range(len(self.FrameData)):
                cycle_ref.FData[i] = c_uint8(self.FrameData[i])
            r = TSMasterAPI. dll.tsapp_add_cyclic_msg_can(byref(cycle_ref), c_float(cycletime))  # send periodically
            if 0 == r:
                logging.info('tsapp_add_cyclic_msg_can: {0}'.format(hex(ID)))
            else:
                logging.warning('tsapp_add_cyclic_msg_can error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))          
        return cycle_ref

    def stop_FrANFrame_Cycle(self,CAN_ref,cycle_CAN_Type='CAN'):
        if cycle_CAN_Type == 'CANFD':
            TSMasterAPI.tsapp_del_cyclic_msg_canfd(CAN_ref)
        else:
            TSMasterAPI.tsapp_del_cyclic_msg_can(CAN_ref)
        pass

    def read_db_signal(self,netname,nodename,msgName,signalname):
        valuehandle = c_double(0)   # .encode("utf8")
        if 0== TSMasterAPI.dll.tscom_can_rbs_get_signal_value_by_element(self.ChannelIndex.value,
                                                                        netname.encode("utf8"),
                                                                        nodename.encode("utf8"),
                                                                        msgName.encode("utf8"),
                                                                        signalname.encode("utf8"),
                                                                        addressof(valuehandle)):
            logging.info('tscom_can_rbs_get_signal_value_by_element  :{0}--{1}--{2}--{3}: {4}'.format(netname,nodename,msgName,signalname,valuehandle.value))
        else:
            logging.warning('tscom_can_rbs_get_signal_value_by_element error :{0}-{1}-{2}-{3}'.format(netname,nodename,msgName,signalname))
        return valuehandle.value

    def write_db_signal(self,netname,nodename,msgName,signalname,value):
        valuehandle = c_double(value)
        if 0 == TSMasterAPI.dll.tscom_can_rbs_set_signal_value_by_element(self.ChannelIndex.value,
                                                                                netname.encode("utf8"),
                                                                                nodename.encode("utf8"),
                                                                                msgName.encode("utf8"),
                                                                                signalname.encode("utf8"),
                                                                                valuehandle):
            logging.info('tscom_can_rbs_set_signal_value_by_element:{0}--{1}--{2}--{3}: {4}'.format(netname,nodename,msgName,signalname,value))  
        else:
            logging.warning('tscom_can_rbs_set_signal_value_by_element error :{0}-{1}-{2}-{3}'.format(netname,nodename,msgName,signalname))                                                                        

    def tsapp_start_logging(self,filename: str): # 开始录制报文
        r = TSMasterAPI.dll.tsapp_start_logging(filename.encode("utf8"))
        if 0 == r:
            logging.info('start_logging Successful :{0}  '.format(r))
        else:
             logging.warning('start_logging error : {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def tsapp_stop_logging(self):   # 停止录制报文
        r = TSMasterAPI.dll.tsapp_stop_logging()
        return r


    def get_fps(self,ID,CAN_Type='CAN'):
        AIdentifier = c_int32(ID)
        FPS = c_int32(0)
        if CAN_Type =='CAN':
            r = TSMasterAPI.dll.tsapp_get_fps_can(self.ChannelIndex.value, AIdentifier, byref(FPS))
        elif CAN_Type =='CANFD':
            r = TSMasterAPI.dll.tsapp_get_fps_canfd(self.ChannelIndex.value, AIdentifier, byref(FPS))
        if 0 == r:
            logging.info('get {0} FPS : {1}/s  '.format(ID,FPS.value))
        else:
            logging.warning('Get ID FPS error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return FPS.value

    def get_bus_statistics(self,cbsBusLoad = 0):
            # typedef enum {
            #              cbsBusLoad = 0, cbsPeakLoad, cbsFpsStdData, cbsAllStdData,
            #                 cbsFpsExtData, cbsAllExtData, cbsFpsStdRemote, cbsAllStdRemote,
            #                 cbsFpsExtRemote, cbsAllExtRemote, cbsFpsErrorFrame, cbsAllErrorFrame	
            #               } TLIBCANBusStatistics
        status = c_int8(0)
        c_cbsBusLoad = c_int8(cbsBusLoad)
        r = TSMasterAPI.dll.tsapp_get_bus_statistics(TSMasterAPI.TLIBApplicationChannelType.APP_CAN.value,self.ChannelIndex.value,c_cbsBusLoad,byref(status))
        if 0 == r:
            logging.info('get_bus_statistics:{0}  '.format(status.value))
        else:
             logging.warning('get_bus_statistics: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return status.value

    def send_CMD_Shell(self,cmdID,cmdstr):
        if len(cmdstr)%7 == 0:
            cmd_array = list(bytearray(cmdstr.encode('ascii')))
        else:
            cmd_array = list(bytearray(cmdstr.encode('ascii'))) + [0x00]*(7-len(cmdstr)%7)
        cmd_array_2D = np.array(cmd_array).reshape(-1,7)
        index_array = np.arange(cmd_array_2D.shape[0])
        send_array = np.insert(cmd_array_2D,0,index_array,axis=1)
        first_frame = [0x88] + [len(cmdstr)>>8] + [(len(cmdstr))%255]+[0,0,0,0,0]
        last_frame = [0xFF] + [0,0,0,0,0,0,0]
        self.send_Frame(cmdID,first_frame)
        for each_data in send_array:
            self.send_Frame(cmdID,each_data)
        self.send_Frame(cmdID,last_frame)
        logging.info('Send string is: {}'.format(cmdstr))

    def read_CMD_Shell(self,cmdID,cmdstr):
        cmd = cmdstr[4:7]
        string = cmdstr[8:]
        start_valid = False
        stop_valid = False
        replay = []
        ALl_data = pd.DataFrame()  
        Cal_data = None
        replay_value = 0
        # if q.qsize()>0:
        if True:
            # for i in range(q.qsize()):
            #     ALl_data = pd.concat([ALl_data,q.get().to_frame().T],ignore_index=True)

            ALl_data , buffer_size = self.read_frame()
            Cal_data = ALl_data[ALl_data['AIdentifier']==cmdID]

            for i in Cal_data.index: #search first frame
                if Cal_data.loc[i].ADatas[0] ==0x88:
                    start_valid = True
                    start = i
                    cmd_len = ((Cal_data.loc[i].ADatas[1]) << 8) + Cal_data.loc[i].ADatas[2]
                    break
                else:
                    start_valid = False
            for i in Cal_data.index:#search last frame
                if Cal_data.loc[i].ADatas[0] ==0xFF:
                    stop_valid = True
                    stop = i
                    break
                else:
                    stop_valid = False
            if start_valid and stop_valid: #search the replay value
                new = Cal_data.iloc[Cal_data.index.get_loc(start)+1:Cal_data.index.get_loc(stop),:]
                for index, row in new.iterrows():
                    replay += row.ADatas[1:8]
                last_value = replay[:cmd_len]
                value_str = bytes(last_value).decode('ascii')
                if cmdstr[0:7] == 'profile':
                    replay_value = value_str
                elif cmd == 'get':
                    replay_value = re.findall('(?<={0} ).*$'.format(string),value_str)[0]
                else:
                    replay_value = value_str
            else:
                replay_value = 'done'
        else:
            replay_value = 'False'
        logging.info('Recieve string is: {}'.format(replay_value))
        return replay_value

    def sendAndread_CMD_Shell(self,cmdID=0x114,cmdstr='cmd',delaytime=100):
        self.fush_q_buff()
        self.send_CMD_Shell(cmdID,cmdstr)
        self.TS_delay(delaytime)
        return self.read_CMD_Shell(cmdID,cmdstr)

    def parse_dbc(self):
        self.dbc_map = []
        r,Node_List_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle,DB_Variable.DT_INT_Node_List_Count,-1,-1)
        if 0 == r:
            Node_List_Count_value = int(Node_List_Count)
            for i in range(Node_List_Count_value):
                node_map = {}
                TX_msg_struct_array = []
                RX_msg_struct_array = []
                FDTX_msg_struct_array = []
                FDRX_msg_struct_array = []
                TX_sig_struct_array =[]
                RX_sig_struct_array = []
                msg_struct_dict =['type','len','ID','period','name','comment','unknow1','unknow2']
                FDmsg_struct_dict =['type','len','ID','period','name','comment','unknow1','unknow2']  
                sig_struct_dict =['ID','unknow1','unknow2','comment','unknow3','unknow4','Start','len',
                                    'factory','offset','default','max ','min','name','unknow5','unknow6','unknow7','unknow8'] 

                r, node_map['node_name'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Node_List_Name, i, -1)
                r, node_map['node_address'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_Address, i, -1)
                r, node_map['node_comment'] = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Node_List_Comment, i, -1)

                r, node_TX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_CAN_Message_List_Count, i, -1)
                TxCAN = int(node_TX_Msg_Count)
                r, node_RX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_CAN_Message_List_Count, i, -1)
                RxCAN = int(node_RX_Msg_Count)

                r, node_FDTX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_FD_Message_List_Count, i, -1)
                TxCANFD = int(node_FDTX_Msg_Count)
                r, node_FDRX_Msg_Count = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_FD_Message_List_Count, i, -1)
                RxCANFD = int(node_FDRX_Msg_Count) 

                r, Tx_signal_list = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_Signal_List_Count, i, -1)
                mTxSgn = int(Tx_signal_list)
                r, Rx_signal_list = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_Signal_List_Count, i, -1)
                mRxSgn = int(Rx_signal_list)

                # for each tx rx CAN message or signal
                for j in range(TxCAN):
                    r, TX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_CAN_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CAN_Message_List_Struct, int(TX_msg_index), -1)
                        if 0 == r :
                            TX_msg_struct_array.append(dict(zip(msg_struct_dict,s.split(b',')[:len(msg_struct_dict)])))
                node_map['TX_msg_struct'] = TX_msg_struct_array

                for j in range(RxCAN):
                    r, RX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_CAN_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CAN_Message_List_Struct, int(RX_msg_index), -1)
                        RX_msg_struct_array.append(dict(zip(msg_struct_dict,s.split(b',')[:len(msg_struct_dict)])))
                node_map['RX_msg_struct'] = RX_msg_struct_array
                
                for j in range(TxCANFD):
                    r, FDTX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_FD_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CANFD_Message_List_Struct, int(FDTX_msg_index), -1)
                        if 0 == r :
                            FDTX_msg_struct_array.append(dict(zip(FDmsg_struct_dict,s.split(b',')[:len(FDmsg_struct_dict)])))
                node_map['FDTX_msg_struct'] = FDTX_msg_struct_array

                for j in range(RxCANFD):
                    r, FDRX_msg_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_FD_Message_List_Message_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_CANFD_Message_List_Struct, int(FDRX_msg_index), -1)
                        if 0 ==r:
                            FDRX_msg_struct_array.append(dict(zip(FDmsg_struct_dict,s.split(b',')[:len(FDmsg_struct_dict)])))
                node_map['FDRX_msg_struct'] = FDRX_msg_struct_array

                for j in range(mTxSgn):
                    r, TX_sig_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_TX_Signal_List_Signal_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Signal_List_Struct, int(TX_sig_index), -1)
                        if 0 ==r:
                            TX_sig_struct_array.append(dict(zip(sig_struct_dict,s.split(b',')[:len(sig_struct_dict)])))
                node_map['TX_sig_struct'] = TX_sig_struct_array

                for j in range(mRxSgn):
                    r, RX_sig_index = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_INT_Node_List_RX_Signal_List_Signal_Index, i, j)
                    if 0 ==r:
                        r, s = TSMasterAPI.tsdb_get_can_db_info(self.dbchandle, DB_Variable.DT_STR_Signal_List_Struct, int(RX_sig_index), -1)
                        if 0 ==r:
                            RX_sig_struct_array.append(dict(zip(sig_struct_dict,s.split(b',')[:len(sig_struct_dict)])))
                node_map['RX_sig_struct'] = RX_sig_struct_array

                self.dbc_map.append(node_map)

        else:
            logging.warning('tsdb_get_can_db_info --- DT_INT_Node_List_Count: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))

        return self.dbc_map
        

class TSCAN_UDS(object):
    def __init__(self,ChannelIndex = TSMasterAPI.CHANNEL_INDEX.CHN1, ASupportFD = 0, AMaxdlc=8, 
                reqID  = 0x72c, ARequestIDIsStd=True,
                resID  = 0x73c, resIsStd =True,
                AFctID = 0x7DF, fctIsStd =True,
                p2_extended = 5000,p2_timeout = 3000,
                s3_clienttime = 3000,s3_servertime = 5000):
        self.ChannelIndex = ChannelIndex
        self.ASupportFD = ASupportFD
        self.AMaxdlc= AMaxdlc
        self.reqID  = reqID
        self.ARequestIDIsStd = ARequestIDIsStd
        self.resID  = resID
        self.resIsStd = resIsStd
        self.AFctID = AFctID
        self.fctIsStd = fctIsStd
        self.p2_extended = p2_extended
        self.p2_timeout = p2_timeout
        self.s3_clienttime = s3_clienttime
        self.s3_servertime = s3_servertime

        self.init_UDS()

    def init_UDS(self):
        self.udsHandle = c_byte(0)
        r = TSMasterAPI.dll.tsdiag_can_create(byref(self.udsHandle), self.ChannelIndex.value, c_byte( self.ASupportFD), c_byte(self.AMaxdlc), 
                                        self.reqID,c_bool(self.ARequestIDIsStd),self.resID,c_bool(self.resIsStd),self.AFctID,c_bool(self.fctIsStd))
        if 0 == r:
            logging.info('UDS Creat successful, The udsHandle is : {0}'.format(self.udsHandle) )
        else:
            logging.warn('UDS Creat error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)) )
        TSMasterAPI.dll.tsdiag_set_p2_extended(self.udsHandle,c_int32(self.p2_extended))
        TSMasterAPI.dll.tsdiag_set_p2_timeout(self.udsHandle,c_int32(self.p2_timeout))
        TSMasterAPI.dll.tsdiag_set_s3_clienttime(self.udsHandle,c_int32(self.s3_clienttime))
        TSMasterAPI.dll.tsdiag_set_s3_servertime(self.udsHandle,c_int32(self.s3_servertime))

    def req_and_res_can(self, AReqDataArray, AReqDataSize,enable_print = True):

        self.AReqdata = (c_uint8*5000)()
        self.AResSize = c_int(5000)
        self.AResponseDataArray = (c_uint8*5000)() 

        sendstr = None
        readstr = None

        for index,datavalue in enumerate(AReqDataArray):
            self.AReqdata[index] = c_uint8(datavalue)

        ResponseDataArray = []
        sendstr = binascii.b2a_hex(bytearray(AReqDataArray),' ')

        #print sent data
        if enable_print:
            logging.info('Send UDS ID : [0x{0:X}]'.format(self.reqID))
            logging.info('Send UDS request size :{0} ---,the send data are <<<{1}>>>'.format(AReqDataSize,sendstr))

        for i in range(1):
            time.sleep(0.05)
            r  = TSMasterAPI.tstp_can_request_and_get_response(self.udsHandle, self.AReqdata, AReqDataSize, self.AResponseDataArray , self.AResSize)
            if 0 == r and self.AResSize.value != 0:
                for i in range(self.AResSize.value):
                    ResponseDataArray.append(self.AResponseDataArray[i])
                if enable_print:
                    readstr = binascii.b2a_hex(bytearray(ResponseDataArray),' ')
                    logging.info('Read UDS reponse size :{0} ---,the read data are <<<{1}>>>\n'.format(self.AResSize.value,readstr))
                break
            else:
                logging.warning('req_and_res_can error: '+ TSMasterAPI.tsapp_get_error_description(r)+'\n')
            #     self.UDS_can_delete()
            #     self.init_UDS()
            #     time.sleep(1)
            #     logging.warning('time delay 1s')
            #     logging.warning('UDS Reopen')

        return ResponseDataArray , self.AResSize.value

    def search_DTC(self, DTC_CMD,expect_DTC,timeout=5):
        start_time = time.time()
        Find_DTC = False
        rep_value = []
        while( (time.time()-start_time) < timeout):
            rep_value,rep_size = self.req_and_res_can(DTC_CMD,len(DTC_CMD),enable_print= False)
            reponse_np = np.array(rep_value)[3:].reshape((-1,4))
            for data in reponse_np.tolist():
                if expect_DTC == data:
                    Find_DTC = True
                    break
                else:
                    Find_DTC = False
            if Find_DTC:
                break
        sendstr = binascii.b2a_hex(bytearray(DTC_CMD),' ')    
        totle_time = time.time()-start_time
        all_reponse = binascii.b2a_hex(bytearray(rep_value),' ')
        logging.info('Read DTC by CMD:{0}---,DTC [{4}] had found {1}---,Totle used time {2} ---, The All reponse are {3} '.format(
            sendstr,Find_DTC,totle_time,all_reponse, binascii.b2a_hex(bytearray(expect_DTC), ' ')))
        
        return Find_DTC,totle_time,rep_value

    def uds_session_control(self,ASubSession: c_byte):
        r = TSMasterAPI.dll.tsdiag_can_session_control(self.udsHandle, ASubSession)
        if 0 == r:
            logging.info('session_control send [ {0} ] successful  '.format(ASubSession))
        else:
            logging.warning('session_control error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def uds_routine_control(self,ARoutineControlType: c_byte,ARoutintID: c_uint16):
        r = TSMasterAPI.dll.tsdiag_can_routine_control(self.udsHandle, ARoutineControlType, ARoutintID)
        if 0 == r:
            logging.info('session_control send [ {0} ] - [ {1} ] successful  '.format(str(ARoutineControlType),str(ARoutintID)))
        else:
            logging.warning('session_control error: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return r

    def uds_security_access_request_seed(self,ALevel: c_int32):
        ARecSeed = []
        AResSize = c_int(100)
        AResponseDataArray = (c_uint8*100)()
        r = TSMasterAPI.dll.tsdiag_can_security_access_request_seed(self.udsHandle, 
                                            ALevel, AResponseDataArray, byref(AResSize))   
        if 0 == r:
            for i in range(AResSize.value):
                ARecSeed.append(AResponseDataArray[i])
            logging.info('session_control send  successful  ')
        else:
            logging.warning('security_access_request_seed: {0}'.format(TSMasterAPI.tsapp_get_error_description(r)))
        return ARecSeed

    def UDS_can_delete(self):
        r = TSMasterAPI.dll.tsdiag_can_delete(self.udsHandle)
        if 0 == r:
            logging.info('UDS_can_delete successful')
        else:
            logging.warning('UDS_can_delete error:{0}'.format(TSMasterAPI.tsapp_get_error_description(r)))


class combineDownload(object):
    def __init__(self) -> None:
        pass

    def parse_file(self,file_path):
        self.file_type = os.path.splitext(file_path)[-1]
        self.binfile_handle = bincopy.BinFile()
        if(self.file_type == '.hex' or self.file_type == '.HEX'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_ihex(fin.read())
        if(self.file_type == '.bin' or self.file_type == '.BIN'):
            with open(file_path, 'rb') as fin:
                self.binfile_handle.add_binary(fin.read())
        if(self.file_type == '.s19'):
            with open(file_path, 'r') as fin:
                self.binfile_handle.add_srec(fin.read())
        logging.info('The file info is:  {0}'.format(file_path,self.binfile_handle.info()) )
        # logging.info(binfile_handle.segments())  #All data
        return self.binfile_handle.segments

    def download(self,candriver,file_path,start_add=0x0,size=0x0):
        download_data =[]
        self.parse_file(file_path)
        for index,segment in enumerate(self.binfile_handle.segments):
            if(self.file_type == '.bin' or self.file_type == '.BIN'):
                start_address = start_add
                segment_size = size
            else:
                start_address = segment.minimum_address
                segment_size = segment.maximum_address - segment.minimum_address
                
            # 34 Server,Request download
            Request_download_CMD = [0x34,00,0x44] + \
                                    [(start_address>>24) & 0xFF] + [(start_address>>16) & 0xFF] + [(start_address>>8) & 0xFF] + [(start_address) & 0xFF] +\
                                    [(segment_size>>24) & 0xFF] + [(segment_size>>16) & 0xFF] + [(segment_size>>8) & 0xFF] + [(segment_size) & 0xFF]
            rep_value,rep_size = candriver.req_and_res_can(Request_download_CMD,len(Request_download_CMD),enable_print= False)

            # 36 Server, start download
            download_data = download_data + list(segment.data)
            download_data_CMD = [0x36,index] + list(segment.data)
            rep_value,rep_size = candriver.req_and_res_can(download_data_CMD,len(download_data_CMD),enable_print= False)

        # 37 Server, stop download
        data_37,rep_size = candriver.req_and_res_can([0x37],1,enable_print= False)

        return download_data,data_37


class HIL_Obj(Thread):
    def __init__(self,send_ref:TSCAN):
        Thread.__init__(self)
        self.all_frame = []
        self.warning_data = []
        self.last_warninh_data = None

        self.CAN_ref = send_ref
        
    def open(self,path = './data/autosave_145924326_RawTarget.csv'):
        logging.info('parse obj file start......, The file if from : {0}'.format(path))
        with open(path) as f:
             reader=csv.reader(f)
             row_num = 0
             frame_data = []
             frame = {}
             for index, row in enumerate(reader):
                 if row[0] == 'START': 
                     Frame_flag = True
                     Frame_num = int(row[1].split(':',1)[1])
                     Frame_type = row[2].split(':',1)[1]
                     row_num =  index
                 if row[0] == 'END': 
                     Frame_flag = False
                     frame['Frame_num'] = Frame_num
                     frame['Frame_type'] = Frame_type
                     frame['Frame_num_total'] = int(row[1].split(':',1)[1])
                     frame['data'] = frame_data
                     self.all_frame.append(frame)
                     frame_data = []
                     frame = {}
                 if Frame_flag:
                     if row[3]!= '' :
                        frame_data.append(np.array(row).astype(float))
                 if index == row_num + 1 :
                    pass
                 if index == row_num + 2 :
                    pass
        logging.info('Parse over')
        self.all_frame = self.all_frame

        return self.all_frame

    def obj_sent(self):
        N = 0

        # enter debug mode
        self.CAN_ref.send_Frame((0x30<<4)+N, [0x31,0x58,0xAF,0xFF,0xFF,0xFF,0xFF,0xFF],'CAN')
        self.CAN_ref.send_Frame((0x20<<4)+N, [0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00],'CAN')
        
        # for index, data in enumerate(all_frame) :
        for data in self.all_frame :    
            start = time.time()
            VehicleSpeedInput = int(data['data'][0][6] * 100)
            yaw_rate = int(data['data'][0][16] * 100)
            obj_num = data['Frame_num_total']
            timeInterval = int(data['data'][0][12])
            if data['Frame_type'] == 'l_bsd':
                N = 4
                pass
            elif data['Frame_type'] == 'r_bsd':
                N = 5
                pass
            # Send vehicle info
            self.CAN_ref.send_Frame(0x3F5, [0x00,0x00,0x00,0x00,0x00,0x00,((VehicleSpeedInput&0xFFFF) >> 8),(VehicleSpeedInput&0xFF)],'CAN')
            self.CAN_ref.send_Frame(0x3F6, [0x00,0x00,0x00,0x00,((yaw_rate>>8) & 0xFF),(yaw_rate&0xFF),0x00,0x00],'CAN')
            # Send Header
            self.CAN_ref.send_Frame((0x60<<4)+N, [obj_num,0x00,0x00,0x20,0x00,0x00,0x00,0x00],'CAN')
            
            #[ID,Range,Velocity,Angle,SNR,Kstate,Vehicle_Speed,X_Lateral,Y_Longitudinal,
            # X_Speed,Y_Speed,Radius,timeInterval,isUse,cntCandiTrk,noisePtr,yaw_rate]
            for index,raw_detail in enumerate(data['data']):
                self.CAN_ref.send_Frame((0x71<<4)+N, [int(raw_detail[0]),
                                            ( int(raw_detail[1]*20) & 0x1FFF) >> 5 ,
                                            ((int(raw_detail[1]*20) & 0x1F  ) << 3) + ((int(raw_detail[2]*10)&0x7FF)>>8),
                                            ( int(raw_detail[2]*10) & 0xFF  ),
                                            ( int(raw_detail[3]*4)  & 0x3FF ) >> 2,
                                            ((int(raw_detail[3]*4)  & 0x03  ) << 6) + ((int(raw_detail[7])  &0x1FF)>>3),
                                            ((int(raw_detail[7])    & 0x07  ) << 5) + 0x00,
                                              int(raw_detail[4]*2)  & 0xFF],'CAN')
                # self.send_Frame((0x71<<4)+N,[1,2,3,4,5,6,7,8],'CAN')
                pass

            # Send Stop，with time
            self.CAN_ref.fush_q_buff()
            self.CAN_ref.send_Frame((0x5F<<4)+N, [0x00,0x00,0x00,0x00,timeInterval,0x00,0x00,0x00],'CAN')
            self.CAN_ref.TS_delay(10)

            # read warning
            totle = None
            warningID = None
            obj_start = time.time()
            while time.time()-obj_start < 0.05:
                totle,buffer_size  = self.CAN_ref.read_frame()
                # print('read warning once need time  is ',time.time()-obj_start)
                if buffer_size > 0:
                    warningID = totle[totle['AIdentifier']==(0x7B<<4)+N]
                    if len(warningID) > 0:
                        self.last_warninh_data = warningID.iloc[0]['ADatas']
                        self.warning_data.append(self.last_warninh_data)
                        break
                    else:
                        self.CAN_ref.TS_delay(1)
            print('elape time is ',time.time()-start)
        pass
    
    def run(self) -> None:
        self.obj_sent()
        return super().run()

# def test():
#     for i in range(5):
#         print(threading.current_thread().name+' test ',i)
#         time.sleep(1)
# thread = threading.Thread(target=test)
# thread.start()

# retrieve application timestamp
# print("Current timestamp(s) is", app.get_timestamp() / 1000000.0)

# run main
if __name__ == "__main__":
    # import os
    # root = os.getcwd()
    # project_DBC_File_CAN = os.path.join(root, r'data\FX12_Matrix_FRM_V1_7_20220531.dbc')
    # print(project_DBC_File_CAN)
    try:
        rbs = TSCAN(drive_type = 'USE_TS_TC1014_DEVICE',   #'USE_TS_TC1014_DEVICE':USE_TS_VIRTUAL_DEVICE
                    configure_baudrate = {'CAN_Type':'CANFD','ArbRate':500,'DataRate':2000,'TermResistor':True}
                    )
        # rbs.load_dbc(project_DBC_File_CAN)
        # rbs.register_event_can_T_R(OnCANevent)
        # rbs.register_event_canfd_T_R(OnCANFDevent)
        rbs.connect_application()
        # rbs.RBS_Config('ChengTech_77G_V2',['CGW_Safety','EPS_Safety','FVC_Safety','APA_Safety','ABS_ESP_Safety'])

        print('send frame')
        # rbs.send_Frame(0x666,[0x61,2,3,4,5,6,7,8,
        #                       0x22,2,3,4,5,6,7,8,
        #                       0x23,2,3,4,5,6,7,8,
        #                       0x24,2,3,4,5,6,7,8,
        #                       0x25,2,3,4,5,6,7,8,
        #                       0x26,2,3,4,5,6,7,8,
        #                       0x27,2,3,4,5,6,7,8,
        #                       0x28,2,3,4,5,6,7,8],'CANFD')
        # rbs.send_Frame(0x114,[0x71,2,3,4,5,6,7,8,],'CAN')
        # rbs.send_Frame(0x777,[0x81,2,3,4,5,6,7,8,],'CAN')
        # rbs.send_Frame(0x444,[0x41,2,3,4,5,6,7,8,],'CAN')

        # print('step1_wait_1000_:::::')
        # rbs.fush_q_buff()
        # rbs.TS_delay(1000)
        # rbs.read_frame()

        # print('step2__wait_2000_:::::') 
        # rbs.fush_q_buff()
        # rbs.TS_delay(2000)
        # rbs.read_frame()

        # print('step2__wait_2000_:::::') 
        # rbs.fush_q_buff()
        # rbs.TS_delay(2000)
        # rbs.read_frame()

        # print('step3__wait_3000_:::::') 
        # rbs.fush_q_buff()
        # rbs.TS_delay(3000)
        # rbs.read_frame()
        t1 = rbs.sendAndread_CMD_Shell(0x114,'profile 0',50)
        print(t1)
        t2= rbs.sendAndread_CMD_Shell(0x114,'cmd get gSmStatusMask 0 L 1',50)
        print(t2)
        # rbs.send_CMD_Shell(0x114,'cmd fsmErrInjection 4 0')
        # t3= rbs.sendAndread_CMD_Shell(0x114,'cmd fsmErrInjection 4 0',50)
        # print(t3)

        # a =rbs.send_CANFrame_Cycle(0x22,[0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88],100)
        # rbs.TS_delay(5000)
        # rbs.stop_FrANFrame_Cycle(a)

        # rbs.write_db_signal('ChengTech_77G_V2','CGW_Safety','ICM_DateTime','ICM_CurrentTimeHour',15)

        # aa = rbs.read_db_signal('ChengTech_77G_V2','CGW_Safety','ICM_DateTime','ICM_CurrentTimeHour')
        # print('read rbs signal value is ',aa)

        # diag = TSCAN_UDS()
        # for i in range (1):
        #     diag.req_and_res_can([0x10,0x03],2)
        # diag.UDS_can_delete()

        # obj = HIL_Obj(rbs)
        # obj.setDaemon(True)
        # obj.open()
        # obj.obj_sent()
        # obj.start()
        # obj.last_warninh_data
        # obj.warning_data

        # rbs.parse_dbc()

        rbs.dis_connect_application()

        print('Over All')
        import sys
        sys.exit(0)

    except Exception as e :
        rbs.dis_connect_application()
        import sys
        import traceback
        print(traceback.print_exc())
        sys.exit(0)
        pass
    
    except KeyboardInterrupt :
        rbs.dis_connect_application()
        import sys
        import traceback
        print(traceback.print_exc())
        sys.exit(0)
        pass
